package com.classroommanagesystem.intercepts;

import com.classroommanagesystem.common.Result;
import com.classroommanagesystem.controller.UserController;
import com.classroommanagesystem.domain.entity.User;
import com.classroommanagesystem.exception.BusinessException;
import com.classroommanagesystem.security.RoleConvertUtil;
import com.classroommanagesystem.service.UserService;
import com.classroommanagesystem.utils.ErrorResponseUtil;
import com.classroommanagesystem.utils.JwtUtil;
import com.classroommanagesystem.utils.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.util.AntPathMatcher;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

/**
 * JwtAuthenticationFilter类用于拦截请求，解析Token并更新SecurityContext
 */
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    // 用于路径匹配的工具类
    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
    // 无需认证的路径列表
    private static final String[] EXCLUDE_PATHS = {
            "/doc.html",
            "/swagger-ui/**",
            "/v3/api-docs/**",
            "/webjars/**",
            "/static/**",
            "/public/**",
            "/favicon.ico"
    };

    // 判断请求路径是否无需认证的方法
    private boolean isExcludedPath(HttpServletRequest request) {
        String path = request.getRequestURI();
        for (String exclude : EXCLUDE_PATHS) {
            if (PATH_MATCHER.match(exclude, path)) return true;
        }
        return false;
    }


    // 从请求中提取Token的方法
    private String getTokenFromRequest(HttpServletRequest request) {
        // 处理token头
        String tokenHeader = request.getHeader("token");
        if (StringUtils.hasText(tokenHeader)) return tokenHeader.trim();

        // 处理 Authorization 头
        String authorizationToken = request.getHeader("Authorization");
        if (StringUtils.hasText(authorizationToken)) {
            // 若带Bearer前缀，截取后面的Token
            if (authorizationToken.startsWith("Bearer ")) return authorizationToken.substring(7).trim();
            // 不带前缀则直接返回
            return authorizationToken.trim();
        }
        // 若以上头均未提取到Token，则返回null
        log.info("未从请求头中提取到Token");
        return null;
    }

    /**
     * 拦截请求，进行Token解析
     */
    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain
    ) throws ServletException, IOException {

        //  如果是跳过认证的路径，直接放行，不执行Token解析
        if (isExcludedPath(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        try {
            // 提取Token（仅对非排除路径执行）
            String token = getTokenFromRequest(request);

            if (!StringUtils.hasText(token)) {
                ErrorResponseUtil.write(response, "token无效，请重新登录");
                return;
            }

            //  提取用户ID
            Long userId = JwtUtil.getUserId(token);

            // 验证Redis中的token（防止注销后仍可用）
            String redisToken = redisTemplate.opsForValue().get("token:" + userId);
            if (!StringUtils.hasText(redisToken) || !redisToken.equals(token))
                throw new BusinessException("token已失效，请重新登录");

            //  加载用户信息（含角色）
            User user = userService.getById(userId);

            if (user == null) throw new BusinessException("用户不存在");
            if (user.getStatus() == 0) throw new BusinessException("用户已被禁用");
            //  提取角色信息
            String roleName = RoleConvertUtil.convertRole(user.getRoleId());

            // 5. 设置安全上下文（关键：后续权限校验直接使用）
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    user.getUsername(),
                    user.getPassword(), // 密码用于后续可能的重新认证
                    Collections.singletonList(new SimpleGrantedAuthority(roleName))
            );
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);

            //  同时存入 ThreadLocal（供业务代码直接获取）
            ThreadLocalUtil.setCurrentId(userId);

        } catch (Exception e) {
            // 若发生异常，则直接返回错误信息
            ErrorResponseUtil.write(response, e.getMessage());
            // 终止后续处理
            return;
        }
        try {
            // 继续执行后续过滤器
            filterChain.doFilter(request, response);
        } finally {
            // 7. 请求结束后清除 ThreadLocal，避免内存泄漏
            ThreadLocalUtil.removeCurrentId();
        }
    }



}